from flask import abort, jsonify
from flask import current_app
from flask import g
from flask import render_template
from flask import request
from flask import session

from info import constants
from info import db
from info.models import News, User, Comment, CommentLike
from info.utils.common import user_login_data
from info.utils.response_code import RET
from . import news_detail_blu


@news_detail_blu.route("/<int:news_id>")
@user_login_data
def news_detail(news_id):

    user = g.user

    # 查询新闻内容用作展示，查询出错和不存在都抛出404异常
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        abort(404)

    if not news:
        # 报404错误，404错误统一显示页面后面再处理
        abort(404)

    # 更新新闻的点击次数
    news.clicks += 1

    # 查询新闻内容用作展示，查询出错和不存在都抛出404异常
    try:
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)

    # 新闻首页的点击排行榜（按点击量来排行）
    news_click = []
    try:
        news_click = News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)

    is_collected = False  # 定义这个变量来表示用户是否收藏当前新闻
    # if 用户已经登录：
    #     判断用户是否收藏当前新闻，如果收藏：
    #         is_collected=True
    if user:
        # 查询当前用户是否已经收藏了当前信息（models.py中的user中建立了关系）
        if news in user.collection_news:
            is_collected = True

    # 刷新页还不能看到刚才发过的评论，因为在展示页面的视图函数中并没有展示新闻的评论列表
    comment = []
    try:
        comment = Comment.query.filter(Comment.news_id == news_id).order_by(Comment.create_time.desc()).all()
    except Exception as e:
        current_app.logger.error(e)


    comment_list = []  # 将所有的评论 .to_dict() 并追加到这个列表返回给前端填数据
    for item in comment:
        comment_list.append(item.to_dict())

    # 登录的用户点赞过的评论传给前端user_like_comments
    user_like_comments = []
    if user:
        for i in user.like_comments:
            user_like_comments.append(i.to_dict())

    # 收藏和已收藏按钮的展示逻辑
    is_collected = False  # is_collected标记用户是否收藏这篇新闻, False表示没收藏
    # if 用户登录了:
    #     if  用户收藏了这边新闻:
    #         is_collected = True
    if user:
        if news in user.collection_news:
            # user.collection_news 来拿到这个user用户所收藏的所有新闻（列表，每一个元素是News的对象）
            is_collected = True
    # 在加载详情页面的时候，也要查询这篇新闻下的所有的评论， 传到模板
    try:
        comments = Comment.query.filter(Comment.news_id==news.id).order_by(Comment.create_time.desc())
    except Exception as e:
        current_app.logger.error(e)
    # 将comments中的所有对象，转成字典
    comments_list = []
    for i in comments:
        comments_list.append(i.to_dict())
    # 将用户的点在评论列表传到模板中,为了明确某条评论有没有被用户点赞
    user_like_comments = []
    if user:
        for i in user_like_comments:
            # user.like_comments 来获取 用户点赞过的所有评论
            user_like_comments.append(i.to_dict())

    # 获取这篇新闻的作者
    author = news.user    # news.user  获取这篇新闻的作者对象

    data = {
        "user": user.to_dict() if user else None,
        "news_click": news_click,  # 点击排行榜
        "news": news.to_dict(),
        "is_collected": is_collected,   # 用户收藏的新闻
        # "comment_list": comment_list,   # 所有的评论
        "comment": comment,
        "user_like_comments": user_like_comments,  # 所有的点赞
        "author": author.to_dict()   # 关注
    }

    return render_template("news/detail.html", data=data)


@news_detail_blu.route("/news_collect", methods=['POST'])
@user_login_data
def news_collect():
    '''
    用户收藏和取消收藏都在这个视图函数
    1、获取登录用户信息
    2、接收参数
    3、判空
    4、查询新闻，并判断是否存在
    5、收藏或者取消收藏
    6、返回成功的响应
    '''

    # 1、获取登录用户信息(没登录不能收藏和取消收藏)
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    # 2、接收客户端发送过来的参数（news_id，action为collect表示要执行收藏，也可以是cancel_collect表示要执行取消收藏）
    data_dict = request.json    # post请求用json
    news_id = data_dict.get("news_id")
    action = data_dict.get("action")

    # 3、判空
    if not news_id:
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    if action not in ("collect", "cancel_collect"):
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 4、查询新闻，判断是否存在
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno = RET.DBERR, errmsg = "查询数据失败")

    if not news:
        return jsonify(errno = RET.NODATA, errmsg = "新闻不存在")

    # 5、收藏或者取消收藏
    if action == "collect":
        # 收藏新闻
        # flask操作模型属性的时候，可以使用列表的操作来完成数据的追加和移除
        user.collection_news.append(news)
    else:
        # 取消收藏新闻
        user.collection_news.remove(news)

    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="数据库操作失败")

    # 6、返回成功的响应
    return jsonify(errno = RET.OK, errmsg = "操作成功")


@news_detail_blu.route("/news_comment", methods=["POST"])
@user_login_data
def news_comment():
    # 1、获取用户登录信息
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    # 2、接收参数
    data_dict = request.json
    news_id = data_dict.get("news_id")
    comment_str = data_dict.get("comment")
    parent_id = data_dict.get("parent_id")
    # 3、判空
    if not all([news_id, comment_str]):
        return jsonify(errno = RET.PARAMERR, errmsg = "参数不足")
    # 4、查询新闻，并判断是否存在
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno = RET.DBERR, errmsg = "查询数据失败")

    if not news:
        return jsonify(errno = RET.NODATA, errmsg = "该新闻不存在")

    # 5、初始化一个评论模型
    comment = Comment()
    comment.user_id = user.id
    comment.news_id = news_id
    comment.content = comment_str
    if parent_id:
        # 如果是回复评论，则需要添加parent_id
        comment.parent_id = parent_id

    # 6、添加到数据库
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存评论数据失败")

    # 7、返回成功的响应
    return jsonify(errno = RET.OK, errmsg = "评论成功", data = comment.to_dict())


@news_detail_blu.route("/comment_like", methods=["POST"])
@user_login_data
def comment_like():
    # 点赞和取消点赞的后端逻辑实现
    '''
    1、获取登录用户信息
    2、获取请求参数、判空  （评论id和action）
    3、查询评论并且判断评论是否存在
    4、根据action的值进行添加和删除(点赞 / 取消点赞成功以后，增加 / 减少评论的点赞数量comment.like_count)
    5、返回操作成功
    '''

    # 1、获取登录用户信息
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    # 2、获取请求参数、判空
    data_dict = request.json
    comment_id = data_dict.get("comment_id")
    action = data_dict.get("action")

    if not all([comment_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    if action not in ("add", "remove"):
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    # 3、查询评论并且判断评论是否存在
    try:
        comment = Comment.query.get(comment_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno = RET.DBERR, errmsg = "查询数据失败")

    if not comment:
        return jsonify(errno = RET.NODATA, errmsg = "评论不存在")

    #
    # if comment_id:
    #     action = 'remove'



    # 4、根据action的值进行添加和删除  add  或者 remove
    if action == 'add':
        user.like_comments.append(comment)      # 用户点过赞的评论信息 like_comments
        # 点赞成功以后，添加评论的点赞数量
        comment.like_count += 1        # # 点赞条数  like_count
    else:
        user.like_comments.remove(comment)
        # 点赞取消以后，删减评论的点赞数量
        comment.like_count -= 1

    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="又是操作失败")

    return jsonify(errno = RET.OK, errmsg = "操作成功")

